//
// Unihan Input Method
//
// Copyright © 2002-2007 Sun Wah Linux Ltd.
//
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//
// $Id: unihan_im.h 815 2007-08-22 03:16:28Z roger $
//

#ifndef __UNIHAN_IM_H
#define __UNIHAN_IM_H

#include <stdlib.h>
#if NEW_PROPERTY
#include "unihan_property.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct _UnihanIM UnihanIM;            /**< @brief UnihanIM context */
typedef struct _UnihanMethods UnihanMethods;  /**< @brief Service methods provided by Unihan */
typedef struct _UnihanStyleList UnihanStyleList;
typedef struct _UnihanStyle UnihanStyle;
typedef struct _UnihanLookupDraw UnihanLookupDraw;
typedef struct _UnihanLookupStart UnihanLookupStart;

typedef enum {
    UNIHAN_TCSC_NO_CONV = 0,
    UNIHAN_TCSC_TO_SIMPLIFIED = 1,
    UNIHAN_TCSC_TO_TRADITIONAL = 2,
    UNIHAN_TCSC_AUTO_TO_SIMPLIFIED = 3,     /**< deprecated */
    UNIHAN_TCSC_AUTO_TO_TRADITIONAL = 4     /**< deprecated */
} UnihanTCSCMode;

typedef enum {
    UserName = 1,
    HostName = 2,
    ProtocolType = 3,
    ClientType = 4,
    DisplayID = 5,
    OSName = 6,
    OSVersion = 7,
    OSArch = 8
} UnihanClientInfoType;

typedef enum {
    UNIHAN_LOG_LEVEL_ERROR      = 1 << 2,
    UNIHAN_LOG_LEVEL_CRITICAL   = 1 << 3,
    UNIHAN_LOG_LEVEL_WARNING    = 1 << 4,
    UNIHAN_LOG_LEVEL_MESSAGE    = 1 << 5,
    UNIHAN_LOG_LEVEL_INFO       = 1 << 6,
    UNIHAN_LOG_LEVEL_DEBUG      = 1 << 7
} UnihanLogLevelFlags;

/**
 * @brief Service methods provided by Unihan
 */
struct _UnihanMethods {
    int (*send_buffer)          (UnihanIM *uim,
                                 void *buf,
                                 size_t buf_size);

    /**
     * @brief Get per-user configuration data.
     * @param uim   %UnihanIM context
     * @param key   key of config data to get
     * @param value pointer to a buffer for receiving the config data.
     *              The caller must not free or modify the buffer.
     * @param len   pointer to a long for receiving the length of config data
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*config_get)           (UnihanIM *uim,
                                 char *key,
                                 char **value,
                                 long *len);

    /**
     * @brief Set per-user configuration data.
     * @param uim   %UnihanIM context
     * @param key   key of config data to get
     * @param value the config data
     * @param len   the length of config data
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*config_set)           (UnihanIM *uim,
                                 char *key,
                                 char *value,
                                 long len);

    /**
     * @brief Draws preedit text in IM client's window.
     * @param uim     %UnihanIM context
     * @param s       the preedit string
     * @param styles  an array of %UnihanStyleList. The length must be the
     *                same as \a s, eg. if \a s has 3 characters, \a styles
     *                must also have 3 elements.
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*preedit_draw)         (UnihanIM *uim, 
                                 char *s, 
                                 UnihanStyleList *styles);

    /**
     * @brief Sets the preedit string's caret (cursor) position.
     * @param uim       %UnihanIM context
     * @param caretPos  position of the caret, 
     *                  0 = on the left of first character
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*preedit_caret_pos)    (UnihanIM *uim, 
                                 int caretPos);

    /**
     * @brief Changes the existing preedit string.
     * @param uim     %UnihanIM context
     * @param s       the new preedit string.
     *                If %NULL, the preedit text between \a pos and \a pos + \a len 
     *                will be deleted.
     * @param styles  an array of %UnihanStyleList; same convention as preedit_draw()
     * @param pos     the start index of the preedit text to change
     * @param len     the length of the text to change.
     *                If 0, \a s is inserted into the preedit text string.
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*preedit_change)       (UnihanIM *uim, 
                                 char *s, 
                                 UnihanStyleList *styles,
                                 int pos, 
                                 int len, 
                                 int caretPos);

    /**
     * @brief Clears the preedit text.
     * @param uim   %UnihanIM context
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*preedit_erase)        (UnihanIM *uim);

    /**
     * @brief Specifies the details of the candidate lookup choice window.
     * @param uim      %UnihanIM context
     * @param lustart  details of the lookup choice window such as
     *                 height, width, title, etc.
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*lookup_start)         (UnihanIM *uim,
                                 UnihanLookupStart *lustart);

    /**
     * @brief Draws the candidate lookup choice window.
     * @details lookup_start() must be called first.
     * @param uim     %UnihanIM context
     * @param ludraw  candidates to draw in the window
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*lookup_draw)          (UnihanIM *uim,
                                 UnihanLookupDraw *ludraw);

    /**
     * @brief Closes the candidate lookup choice window.
     * @param uim   %UnihanIM context
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*lookup_done)          (UnihanIM *uim);

    /**
     * @brief Shows a string in the status window.
     * @param uim     %UnihanIM context
     * @param s       string to show in status window, NULL to clear the window
     * @param styles  (currently unused)
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*status_draw)          (UnihanIM *uim, 
                                 char *s, 
                                 UnihanStyleList *styles);

    /**
     * @brief Commits a string to the IM client.
     * @param uim   %UnihanIM context
     * @param s     the string to commit
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*commit_string)        (UnihanIM *uim, 
                                 char *s);

    /**
     * @brief Gets the locale of the current user.
     * @param uim     %UnihanIM context
     * @param locale  pointer to a string to receive the locale, eg. zh_CN, zh_HK, zh_TW.
     *                The caller must not free or modify the returned string.
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*locale_get)           (UnihanIM *uim,
                                 char **locale);

    /**
     * @brief Gets the current traditional/simplified mode.
     * @param uim       %UnihanIM context
     * @param tcscMode  a pointer to a buffer to receive the current TC/SC mode
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*tcsc_mode_get)        (UnihanIM *uim,
                                 UnihanTCSCMode *tcscMode);

    /**
     * @brief Performs traditional/simplified conversion.
     * @param uim        %UnihanIM context
     * @param tcscMode   the kind of conversion to perform
     * @param orig       the string to be converted
     * @param converted  the converted string, newly allocated
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*tcsc_do_conv)         (UnihanIM *uim,
                                 UnihanTCSCMode tcscMode,
                                 char *orig,
                                 char **converted);

    /**
     * @brief Allocates temporary memory.
     * @details The allocated memory will be freed by Unihan after the current
     *          event handler callback returns.
     * @param uim   %UnihanIM context
     * @param len   size of memory to allocate
     * @param mem   pointer to a void* to hold the newly allocated memory
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*mem_alloc)            (UnihanIM *uim,
                                 size_t len,
                                 void **mem);

    /**
     * @param uim   %UnihanIM context
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*client_info_get)      (UnihanIM *uim,
                                 UnihanClientInfoType type,
                                 char **info);

    /**
     * @brief Checks current fullwidth/halfwidth mode.
     * @param uim   %UnihanIM context
     * @returns %TRUE if in fullwidth mode, %FALSE if not
     */
    int (*is_fullwidth)         (UnihanIM *uim);

    /**
     * @brief Checks current Chinese/English punctuation mode.
     * @param uim   %UnihanIM context
     * @returns %TRUE if in Chinese punctuation mode, %FALSE if not
     */
    int (*is_chinesepunc)       (UnihanIM *uim);

    /**
     * @brief Checks current Shuangpin mode.
     * @param uim   %UnihanIM context
     * @returns %TRUE if in Shangpin mode, %FALSE if not
     */
    int (*is_shuangpin)         (UnihanIM *uim);

    /**
     * @brief Makes the IM client beep.
     * @param uim   %UnihanIM context
     * @returns 0 if no error, > 0 if error occurs.
     */
    int (*beep)                 (UnihanIM *uim);

    /**
     * @brief Begins phrase matching mode.
     * @param uim   %UnihanIM context
     * @param s     key to match for phrases
     * @returns 0 if no phrases found, 1 if phrases are found.
     */
    int (*match_phrase)         (UnihanIM *uim,
                                 char *s);

    /**
     * @brief Logs debug information.
     * @param uim   %UnihanIM context
     */
    void (*log)                 (UnihanIM *uim,
                                 UnihanLogLevelFlags log_level,
                                 const char *format,
                                 ...);

#if NEW_PROPERTY
    int (*properties_register)  (UnihanIM *uim,
                                 const UnihanPropertyList *property_list, 
                                 char* imid);
    int (*properties_update)    (UnihanIM *uim,
                                 const UnihanPropertyList *property_list);
#endif
};

struct _UnihanIM {
    void *privateData;  // privateData is just the im-sdk session struct
    char *id;           /**< @brief the input method ID */
    char *module_id;    /**< @brief the input module ID */
    char *host_name;
    char *user_name;

    /**
     * These are the private data pointers, which allows input methods
     * to store data needed for operation. Because each input module
     * in Unihan may be used by more than one program and more than one
     * user at anytime, input modules must not use global and/or static
     * variables to store information; instead these pointers must be
     * used. Which pointer to use depends on the lifecycle of the data.
     *
     * imUserData is available for use from when unihan_im_module_get_info()
     * is called. You can think of this data as system-wide.
     */
    void *imUserData;

    /**
     * These are the private data pointers, which allows input methods
     * to store data needed for operation. Because each input module
     * in Unihan may be used by more than one program and more than one
     * user at anytime, input modules must not use global and/or static
     * variables to store information; instead these pointers must be
     * used. Which pointer to use depends on the lifecycle of the data.
     *
     * desktopUserData is per-desktop data available from when init()
     * is called, until done() is called. You can think of this data
     * as user-wide.
     */
    void *desktopUserData;

    /**
     * These are the private data pointers, which allows input methods
     * to store data needed for operation. Because each input module
     * in Unihan may be used by more than one program and more than one
     * user at anytime, input modules must not use global and/or static
     * variables to store information; instead these pointers must be
     * used. Which pointer to use depends on the lifecycle of the data.
     *
     * sessionUserData is per-session data available from when 
     * create_session() is called, until destroy_session() is called.
     */
    void *sessionUserData;

    UnihanMethods *m;   /**< @brief methods Unihan provides that input methods can call */
};

typedef enum {
    SHIFT_MODIFIER = 1,
    CTRL_MODIFIER = 2,
    META_MODIFIER = 4,
    ALT_MODIFIER = 8,
    ALT_GRAPH_MODIFIER = 32
} IMKeyModifier;

typedef enum {
    IM_NOTHING = -1,
    IM_FOCUS = 1,
    IM_KEY = 2,
    IM_CONFIG_CHANGE = 3,
    IM_SWITCH = 4,
    IM_PROPERTY_TOGGLED = 5,
    IM_PROPERTY_REGISTER = 6,
    IM_USER_TABLE = 7,
    IM_LOOKUP_PAGE_TURN = 8,
    IM_LOOKUP_SELECT = 9
} IMEventType;

typedef struct _IMKeyEvent {
    IMEventType type;
    int keyCode;
    int keyChar;
    int modifier;
} IMKeyEvent;

typedef struct _IMFocusEvent {
    IMEventType type;
    int focused;
} IMFocusEvent;

typedef struct _IMConfigChangeEvent {
    IMEventType type;
    char *key;
    int value;
} IMConfigChangeEvent;

typedef struct _IMSwitchEvent {
    IMEventType type;
    int on;
} IMSwitchEvent;

typedef struct _IMPropertyToggledEvent {
    IMEventType type;
    char *key;
} IMPropertyToggledEvent;

typedef struct _IMPropertyRegisterEvent {
    IMEventType type;
    char *imid;
} IMPropertyRegisterEvent;

typedef struct _IMUserTableEvent {
    IMEventType type;
    void *table;
    int numItem;
} IMUserTableEvent;

typedef struct _IMLookupPageTurn {
    IMEventType type;
    int direction;
} IMLookupPageTurnEvent;

typedef struct _IMLookupSelect {
    IMEventType type;
    int num;
} IMLookupSelectEvent;

typedef union _IMEvent {
    IMEventType type;
    IMKeyEvent key;
    IMFocusEvent focus;
    IMConfigChangeEvent configChange;
    IMSwitchEvent switched;
    IMPropertyToggledEvent propertyToggled;
    IMPropertyRegisterEvent propertyRegister;
    IMUserTableEvent table;
    IMLookupPageTurnEvent lookupPageTurn;
    IMLookupSelectEvent lookupSelect;
} IMEvent;

typedef struct _IMMethods {
    int (*init)(UnihanIM *);
    int (*done)(UnihanIM *);
    int (*create_session)(UnihanIM *);
    int (*destroy_session)(UnihanIM *);
    int (*handle_event)(UnihanIM *, IMEvent *);
} IMMethods;

typedef struct _IMInfo IMInfo;
struct _IMInfo {
    char *id;
    char *name;
    char *version;
    void *imUserData;
    IMMethods *methodTable;
    IMInfo *next;
#if NEW_PROPERTY
    UnihanPropertyArgList proplist;
    IMConfig *config;
#endif
};

typedef enum {
    UNIHAN_IM_API_VERSION = 1,
    UNIHAN_IM_MODULE_ID = 2,
    UNIHAN_IM_MODULE_NAME = 3,
    UNIHAN_IM_MODULE_VERSION = 4,
    UNIHAN_IM_MODULE_IM_LIST = 5
} UnihanIMModuleArgID;

typedef struct {
    UnihanIMModuleArgID id;
    void *value;
} UnihanIMModuleArgList;

struct _UnihanStyleList {
    unsigned int numStyles;
    UnihanStyle *style;
};

typedef enum {
    UNIHAN_STYLE_DECORATION = 0,
    UNIHAN_STYLE_FOREGROUND_RGB = 1,
    UNIHAN_STYLE_BACKGROUND_RGB = 2
} UnihanStyleType;

#define UNIHAN_RGB_COLOR(red,green,blue)  (int)((red<<16) + (green<<8) + blue)

struct _UnihanStyle {
    UnihanStyleType type;
    int value;
};

typedef enum {
    UNIHAN_LOOKUP_DIRECTION_RIGHT = 0,
    UNIHAN_LOOKUP_DIRECTION_DOWN = 1
} UnihanLookupDirection;

struct _UnihanLookupStart {
    int choicePerWindow;
    int numColumns;
    int numRows;
    UnihanLookupDirection direction;
};

typedef enum {
    UNIHAN_LOOKUP_MODE_NORMAL = 0,
    UNIHAN_LOOKUP_MODE_PHRASE = 1
} UnihanLookupMode;

struct _UnihanLookupDraw {
    UnihanLookupMode mode;
    int numChoices;
    int selected;
    int currentChoice;
    int totalChoices;
    char *title;
    char **label;
    UnihanStyleList *labelStyles;
    char **value;
    UnihanStyleList *valueStyles;
};

typedef struct _SymbolUserTable {
    int modifier;
    int keyCode;
    char *symbol;
} SymbolUserTable;

typedef struct _WordUserTable {
    char *key;
    char *word;
} WordUserTable;

#ifndef TRUE
# define TRUE 1
#endif

#ifndef FALSE
# define FALSE 0
#endif

#ifdef __cplusplus
}
#endif

#endif /* __UNIHAN_IM_H */

// vi:ts=4:sw=4:nowrap:cin:expandtab
